<template>
  <el-drawer
    :append-to-body="true"
    :wrapperClosable="false"
    :title="title[openType]"
    size="1344px"
    :visible="show"
    @close="handleClose"
  >
    <div class="container_component">
      <div class="knowledge_points">知识点位置：{{ ancestorsName }}</div>
      <div class="search_collect">
        <template v-if="enterType == '随即策略'">
          <div class="item" v-if="topicType == 0">
            <div class="label">单选题</div>
            <el-input-number
              size="mini"
              class="input_number"
              placeholder="请输入"
              v-model="form.singleChoiceCount"
              controls-position="right"
              :precision="0"
              :min="0"
              :step="1"
            ></el-input-number>
          </div>
          <div class="item" v-if="topicType == 1">
            <div class="label">多选题</div>
            <el-input-number
              size="mini"
              class="input_number"
              placeholder="请输入"
              v-model="form.multipleChoiceCount"
              controls-position="right"
              :precision="0"
              :min="0"
              :step="1"
            ></el-input-number>
          </div>
          <div class="item" v-if="topicType == 3">
            <div class="label">填空题</div>
            <el-input-number
              size="mini"
              class="input_number"
              placeholder="请输入"
              v-model="form.fillInTheBlankCount"
              controls-position="right"
              :precision="0"
              :min="0"
              :step="1"
            ></el-input-number>
          </div>
          <div class="item" v-if="topicType == 2">
            <div class="label">判断题</div>
            <el-input-number
              size="mini"
              class="input_number"
              placeholder="请输入"
              v-model="form.judgeCount"
              controls-position="right"
              :precision="0"
              :min="0"
              :step="1"
            ></el-input-number>
          </div>
          <div class="item" v-if="topicType == 4 || topicType == 5">
            <div class="label">简答题</div>
            <el-input-number
              size="mini"
              class="input_number"
              placeholder="请输入"
              v-model="form.shortAnswerCount"
              controls-position="right"
              :precision="0"
              :min="0"
              :step="1"
            ></el-input-number>
          </div>
        </template>
        <template v-else>
          <div class="item">
            <div>单选题</div>
            <el-input-number
              size="mini"
              class="input_number"
              placeholder="请输入"
              v-model="form.singleChoiceCount"
              controls-position="right"
              :precision="0"
              :min="0"
              :step="1"
            ></el-input-number>
          </div>
          <div class="item">
            <div>多选题</div>
            <el-input-number
              size="mini"
              class="input_number"
              placeholder="请输入"
              v-model="form.multipleChoiceCount"
              controls-position="right"
              :precision="0"
              :min="0"
              :step="1"
            ></el-input-number>
          </div>
          <div class="item">
            <div>填空题</div>
            <el-input-number
              size="mini"
              class="input_number"
              placeholder="请输入"
              v-model="form.fillInTheBlankCount"
              controls-position="right"
              :precision="0"
              :min="0"
              :step="1"
            ></el-input-number>
          </div>
          <div class="item">
            <div>判断题</div>
            <el-input-number
              size="mini"
              class="input_number"
              placeholder="请输入"
              v-model="form.judgeCount"
              controls-position="right"
              :precision="0"
              :min="0"
              :step="1"
            ></el-input-number>
          </div>
          <div class="item">
            <div>简答题</div>
            <el-input-number
              size="mini"
              class="input_number"
              placeholder="请输入"
              v-model="form.shortAnswerCount"
              controls-position="right"
              :precision="0"
              :min="0"
              :step="1"
            ></el-input-number>
          </div>
        </template>
        <div class="btns">
          <el-button
            v-if="!showSendLoading"
            @click="generateTopic"
            type="primary"
            size="mini"
          ><span v-if="topicList.length > 0">重新</span>生成
          </el-button
          >
          <el-button
            v-else
            @click="stopCreateTopic"
            type="primary"
            size="mini"
          >
            <img
              class="stop_loading_img"
              src="@/assets/image_ai/loading_img.png"
              alt=""
            />
            停止
          </el-button>
        </div>
      </div>
      <div class="topic_content" ref="topicBox" @scroll="handleChatBoxScroll">
        <template v-if="topicList.length > 0">
          <div
            class="topic_collect"
            v-for="(item, index) in topicList"
            :key="index"
          >
            <div v-if="item.showType" class="topic_type">
              {{ topicTypeText[item.type] }}
            </div>
            <div class="item_all">
              <el-checkbox
                v-if="multiDelete"
                class="selected_box"
                v-model="item.selected"
              ></el-checkbox>
              <div class="topic_item">
                <div class="left">
                  <div class="topic_title">
                    <formula-renderer
                      :content="`${index + 1}、${decodeHTMLEntities(
                          item.question
                        )}`"
                    />
                  </div>
                  <div
                    class="topic_option"
                    v-if="['choice', 'multi_choice'].includes(item.type)"
                  >
                    <div
                      class="option_item"
                      v-for="(optionItem, optionIndex) in item.options"
                      :key="optionIndex"
                    >
                      <formula-renderer
                        :content="decodeHTMLEntities(optionItem)"
                      />
                    </div>
                  </div>
                  <div class="answer">
                    <formula-renderer
                      :content="`答案:${decodeHTMLEntities(item.answer)}`"
                    />
                  </div>
                  <div class="resolve" v-if="item.resolve">
                    <formula-renderer
                      :content="`解析:${decodeHTMLEntities( item.resolve)}`"
                    />
                  </div>
                </div>
                <div class="right">
                  <div class="right_item">
                    <el-select
                      size="mini"
                      placeholder="请选择难度"
                      v-model="item.difficulty"
                    >
                      <el-option
                        v-for="topicItem in topicDifficulty"
                        :key="topicItem.value"
                        :label="topicItem.label"
                        :value="topicItem.value"
                      />
                    </el-select>
                  </div>
                  <div class="right_item">
                    <div @click="editTopic(item)" class="item_icon">
                      <div class="edit"></div>
                    </div>
                    <div class="line"></div>
                    <div @click="delTopic(index)" class="item_icon">
                      <div class="delete"></div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </template>
        <template v-if="topicList.length == 0 && !showSendLoading">
          <el-empty
            style="margin-top: 80px"
            description="暂无题目生成"
          ></el-empty>
        </template>
        <template v-if="showSendLoading">
          <div class="loading_item">
            <div class="loading_img_box">
              <img
                class="loading_img"
                src="@/assets/image_ai/loading_green.png"
                alt=""
              />
              <div class="loading_text">正在生成题目...</div>
            </div>
          </div>
        </template>
      </div>
      <div class="bottom_btns">
        <div class="left">
          <el-button
            v-if="!multiDelete"
            :disabled="topicList.length == 0 || showSendLoading"
            @click="showMultiDelete"
            plain
            type="danger"
            size="small"
          >批量删除
          </el-button>
          <template v-if="multiDelete">
            <el-checkbox v-model="selectAll">全选</el-checkbox>
            <div @click="multiDeleteFun" class="del_text">
              删除
            </div>
            <div @click="canelDelete" class="close_text">
              取消
            </div>
          </template>
        </div>
        <div class="right">
          <el-button size="small" @click="handleClose">取消</el-button>
          <el-button
            size="small"
            :disabled="topicList.length == 0 || showSendLoading"
            @click="addAllTopic"
            type="primary"
          >
            添加({{ topicList.length }})
          </el-button>
        </div>
      </div>
    </div>
    <!--  编辑题目弹窗  -->
    <editTopicDrawer
      :show.sync="showEdit"
      :topicItem="topicItem"
      @updateTopic="updateTopic"
    ></editTopicDrawer>
  </el-drawer>
</template>

<script>
import ws from '@/plugins/websocket'
import { generateQuestionApi, importQuestionApi, stopGenerateQuestionApi } from '@/api/tongyi/tongyi'
import { getAncestorsNameApi } from '@/api/course/course'
import editTopicDrawer from './editTopicDrawer'
import { v4 as uuidv4 } from 'uuid'

export default {
  name: 'AIoutTopicDrawer',
  components: {
    editTopicDrawer
  },
  props: {
    show: {
      type: Boolean,
      default: false
    },
    openType: {
      type: Number,
      default: 1
    },
    courseId: {
      type: [Number, String],
      default: ''
    },
    topicType: {
      type: [String],
      default: ''
    },
    enterType: {
      type: [String],
      default: ''
    },
    containerId: {
      type: [Number, String],
      default: ''
    },
    titleId: {
      type: [Number, String],
      default: ''
    },
    indexId: {
      type: [Number, String],
      default: ''
    }
  },
  watch: {
    show(val) {
      if (val) {
        this.requestId = uuidv4().replace(/-/g, '')
        this.initWebSocket()
        this.getAncestorsName()
      } else {
        ws.disconnect()
      }
    },
    selectAll(value) {
      if (value) {
        this.topicList.forEach((item) => {
          item.selected = true
        })
      } else {
        this.topicList.forEach((item) => {
          item.selected = false
        })
      }
    }
  },
  data() {
    return {
      requestId: null,
      topicItem: {},
      topicTypeText: {
        choice: '单选题',
        multi_choice: '多选题',
        judgement: '判断题',
        filling: '填空题',
        QA: '简答题'
      },
      topicDifficulty: [
        {
          label: '简单',
          value: '简单'
        },
        {
          label: '中等',
          value: '中等'
        },
        {
          label: '困难',
          value: '困难'
        },
        {
          label: '不限难度',
          value: '不限难度'
        }
      ],
      multiDelete: false,
      showEdit: false,
      selectAll: false,
      showSendLoading: false,
      showHtmlLoading: false,
      ancestorsName: '--',
      msgData: '',
      parseQueue: [], // 待解析数据队列
      isParsing: false, // 防重处理标志
      parseTimer: null, // 延迟处理定时器
      autoScroll: true,
      title: {
        0: 'AI出题(联网出题)',
        1: 'AI出题(基于课程内容)'
      },
      topicList: [],
      form: {
        singleChoiceCount: undefined,
        multipleChoiceCount: undefined,
        fillInTheBlankCount: undefined,
        judgeCount: undefined,
        shortAnswerCount: undefined
      }
    }
  },
  methods: {
    canelDelete() {
      this.topicList.forEach((item) => {
        item.selected = false
      })
      this.selectAll = false
      this.multiDelete = false
    },
    decodeHTMLEntities(str) {
      if (typeof str === 'string') {
        const entityMap = {
          '&lt;': '<',
          '&gt;': '>',
          '&amp;': '&',
          '&quot;': '"',
          '&apos;': '\'',
          '&copy;': '©',
          '&reg;': '®',
          '&trade;': '™',
          '&euro;': '€',
          '&pound;': '£',
          '&yen;': '¥'
        }
        // 构建正则表达式，匹配所有键（如 &lt;、&gt; 等）
        const regex = new RegExp(Object.keys(entityMap).join('|'), 'g')
        // 替换函数，根据匹配到的实体返回对应的字符
        return str.replace(regex, (match) => entityMap[match])
      } else {
        return str
      }
    },
    updateTopic(e) {
      console.log(e)
      // 使用 findIndex 查找元素索引
      this.topicList = this.topicList.map(item =>
        item.topicId === e.topicId ? e : item
      );
      // 只在必要时才重新排序
      this.topicList = this.sortTopic(this.topicList);
    },
    multiDeleteFun() {
      let select = 0
      this.topicList.forEach((item) => {
        if (item.selected) {
          select++
        }
      })
      if (select == 0) {
        this.$modal.msgWarning('请选择要删除的题目')
        return
      }
      this.topicList = this.topicList.filter((item) => {
        return !item.selected
      })
      this.multiDelete = false
    },
    showMultiDelete() {
      this.multiDelete = true
    },
    delTopic(index) {
      this.topicList.splice(index, 1)
    },
    editTopic(item) {
      this.topicItem = item
      this.showEdit = true
    },
    async addAllTopic() {
      const loading = this.$loading({
        lock: true,
        text: '正在处理',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.3)'
      })
      let topicList = JSON.parse(JSON.stringify(this.topicList))
      topicList.forEach((value) => {
        value.courseId = this.courseId
        value.indexId = this.indexId
        value.answer = JSON.stringify(value.answer)
        value.options = JSON.stringify(value.options)
      })
      let params = {
        containerId: this.containerId,
        indexId: this.indexId,
        titleId: this.titleId,
        topicList: topicList
      }
      try {
        let res = await importQuestionApi(params)
        const { code } = res
        if (code == 200) {
          this.$message.success('导入成功')
          this.handleClose()
          this.$emit('updateData')
        }
      } catch (e) {
        console.error(e)
      } finally {
        loading.close()
      }
    },
    async stopCreateTopic() {
      try {
        let res = await stopGenerateQuestionApi(this.requestId)
        const { code } = res
        if (code == 200) {
          this.showSendLoading = false
          if (this.showHtmlLoading) {
            this.showHtmlLoading = false
          }
          this.$message.success('停止成功')
        }
      } catch (e) {
        console.error(e)
      }
    },
    async generateQuestion(params) {
      try {
        let res = await generateQuestionApi(params)
        const { code } = res
        if (code == 200) {
          console.log('AI出题>>>>>>')
        }
      } catch (e) {
        console.error(e)
      }
    },
    async getAncestorsName() {
      try {
        let res = await getAncestorsNameApi(this.indexId)
        const { code, msg } = res
        if (code == 200) {
          this.ancestorsName = msg
        }
      } catch (e) {
        console.error(e)
      }
    },
    // 初始化websocket
    initWebSocket() {
      let hostname = window.location.hostname
      const local = hostname === 'localhost' || /^(\d{1,3}\.){3}\d{1,3}$/.test(hostname) ? 'ws://' + hostname + ':9208' : 'wss://' + hostname + '/cloud'
      let url = local + `/ws/generateQuestionWS/${this.requestId}`
      ws.connect(url, this.handleMessage, false)
    },
    //  接收服务器推送的信息
    handleMessage(data) {
      if (this.showHtmlLoading && this.topicList.length > 0) {
        this.showHtmlLoading = false
      }
      // 1. 处理特殊控制消息
      if (data === 'ConversationMessageCompleted') {
        this.showSendLoading = false
        if (this.showHtmlLoading) {
          this.showHtmlLoading = false
        }
        setTimeout(() => {
          this.topicList = this.sortTopic(this.topicList)
        }, 100)
        return
      }

      // 2. 将数据放入队列（而不是直接处理）
      this.parseQueue.push(data)

      // 3. 延迟处理（防抖）
      clearTimeout(this.parseTimer)
      this.parseTimer = setTimeout(() => {
        this.processMessageQueue()
      }, 100) // 适当调整延迟时间
    },
    sortTopic(topiclist) {
      const seenTypes = new Set()
      return topiclist.map((item) => {
        item.showType = true
        item.topicId = item.topicId || uuidv4().replace(/-/g, '')
        item.showType = !seenTypes.has(item.type)
        seenTypes.add(item.type)
        delete item.score
        return item
      })
    },
    processMessageQueue() {
      if (this.isParsing) return

      this.isParsing = true

      try {
        // 合并队列中的所有数据
        const combinedData = this.parseQueue.join('')
        this.parseQueue = [] // 清空队列

        // 追加到主缓冲区
        this.msgData += combinedData

        // 改进的JSON提取逻辑
        let extracted = []
        let remaining = this.msgData

        while (true) {
          // 尝试找到第一个完整JSON对象
          const { object, rest } = this.tryExtractJSON(remaining)
          if (!object) break

          extracted.push(object)
          remaining = rest
        }

        // 处理提取到的数据
        if (extracted.length > 0) {
          this.topicList.push(...extracted)
          this.$nextTick(() => {
            // 可选：滚动到最新消息
            this.scrollToBottom()
          })
        }

        // 保留未处理数据
        this.msgData = remaining
      } finally {
        this.isParsing = false
      }
    },
    // 更安全的JSON提取方法
    tryExtractJSON(str) {
      let stack = []
      let inString = false
      let escape = false
      let startIdx = -1

      for (let i = 0; i < str.length; i++) {
        const c = str[i]

        if (escape) {
          escape = false
          continue
        }

        if (c === '\\') {
          escape = true
          continue
        }

        if (c === '"') {
          inString = !inString
        }

        if (!inString) {
          if (c === '{') {
            if (stack.length === 0) startIdx = i
            stack.push(c)
          } else if (c === '}') {
            stack.pop()
            if (stack.length === 0 && startIdx !== -1) {
              try {
                const jsonStr = str.slice(startIdx, i + 1)
                const jsonObj = JSON.parse(jsonStr)
                return {
                  object: jsonObj,
                  rest: str.slice(i + 1)
                }
              } catch (e) {
                console.warn('JSON解析失败:', e)
                // 继续寻找下一个可能的JSON
                startIdx = -1
              }
            }
          }
        }
      }

      return { object: null, rest: str }
    },
    scrollToBottom(force = false) {
      if (force || this.autoScroll) {
        this.$nextTick(() => {
          const container = this.$refs.topicBox
          if (container) {
            // 直接赋值（兼容性好）
            container.scrollTop = container.scrollHeight
          }
        })
      }
    },
    handleChatBoxScroll() {
      const container = this.$refs.topicBox
      if (!container) return
      // 判断是否接近底部（20px 缓冲）
      this.autoScroll = container.scrollTop + container.clientHeight >=
        container.scrollHeight - 20
    },
    generateTopic() {
      if (
        !this.form.singleChoiceCount &&
        !this.form.multipleChoiceCount &&
        !this.form.fillInTheBlankCount &&
        !this.form.judgeCount &&
        !this.form.shortAnswerCount
      ) {
        this.$modal.msgWarning('生成题目数量须大于0')
        return
      }
      this.topicList = []
      let params = {
        ...this.form,
        requestId: this.requestId,
        courseId: this.courseId,
        isNet: this.openType,
        indexId: this.indexId
      }
      this.generateQuestion(params)
      this.showSendLoading = true
      this.showHtmlLoading = true
    },
    handleClose() {
      ws.disconnect()
      this.topicList = []
      this.parseQueue = []
      this.msgData = ''
      this.ancestorsName = ''
      this.showSendLoading = false
      this.selectAll = false
      this.multiDelete = false
      this.showHtmlLoading = false
      this.form = {
        singleChoiceCount: undefined,
        multipleChoiceCount: undefined,
        fillInTheBlankCount: undefined,
        judgeCount: undefined,
        shortAnswerCount: undefined
      }
      this.isParsing = false
      this.parseTimer = null
      this.$emit('update:show', false)
    }
  }
}
</script>

<style scoped lang="scss">
@import "../../../assets/styles/mixin.scss";

.container_component {
  width: 100%;
  border-top: 1px solid #EBEBEB;
  padding: 14px 24px;
  box-sizing: border-box;

  .knowledge_points {
    font-family: PingFangSC, PingFang SC, sans-serif;
    font-weight: 400;
    font-size: 16px;
    color: #333333;
    margin-bottom: 26px;
  }

  .search_collect {
    display: flex;
    align-items: center;
    gap: 0 47px;

    .item {
      display: flex;
      align-items: center;
      gap: 0 12px;

      .label {
        font-family: PingFangSC, PingFang SC, sans-serif;
        font-weight: 400;
        font-size: 16px;
        color: #333333;
      }

      .input_number {
        width: 108px !important;
      }
    }
  }

  .topic_content {
    margin-top: 16px;
    width: 100%;
    height: calc(100vh - 248px);
    overflow: auto;
    display: flex;
    flex-direction: column;
    gap: 16px 0;

    .topic_collect {
      display: flex;
      flex-direction: column;
      gap: 10px 0;

      .topic_type {
        margin-bottom: 6px;
      }

      .item_all {
        display: flex;
        gap: 0 16px;
        padding-right: 10px;
        box-sizing: border-box;

        .selected_box {
          margin-top: 50px;
          width: 20px;
        }

        .topic_item {
          width: 100%;
          display: flex;
          justify-content: space-between;
          padding: 16px 16px 16px 24px;
          box-sizing: border-box;
          border-radius: 6px;
          border: 1px solid #ebebeb;

          .left {
            .topic_title {
              width: 1000px;
              color: #333333;
              font-size: 16px;
              font-weight: bold;
              font-family: PingFangSC, PingFang SC, sans-serif;
            }

            .topic_option {
              margin-top: 10px;
              width: 1000px;
              display: flex;
              flex-direction: column;
              gap: 8px 0;

              .option_item {
                color: #333333;
              }
            }

            .answer {
              margin-top: 10px;
              width: 1000px;
              color: #28b28b;
            }

            .resolve {
              margin-top: 10px;
              width: 1000px;
              color: #666666;
            }
          }

          .right {
            width: 110px;
            display: flex;
            flex-direction: column;
            gap: 8px 0;

            .right_item {
              width: 100%;
              display: flex;
              justify-content: space-between;
              align-items: center;

              .ipt {
                width: 90px !important;
              }

              .item_icon {
                width: 50%;
                display: flex;
                justify-content: center;
                align-items: center;
                padding: 8px 0;
                box-sizing: border-box;
                border-radius: 2px;
                cursor: pointer;

                &:hover {
                  background: rgba(224, 224, 224, 0.4);

                  .edit {
                    background: url("../../../assets/image_ai/edit_act_icon.png");
                    background-size: 100% 100%;
                  }

                  .delete {
                    background: url("../../../assets/image_ai/del_act_icon.png");
                    background-size: 100% 100%;
                  }
                }

                .edit {
                  width: 16px;
                  height: 16px;
                  background: url("../../../assets/image_ai/edit_icon.png");
                  background-size: 100% 100%;
                }

                .delete {
                  width: 16px;
                  height: 16px;
                  background: url("../../../assets/image_ai/delete_icon.png");
                  background-size: 100% 100%;
                }
              }

              .line {
                width: 1px;
                height: 16px;
                background: #f3f3f3;
              }
            }
          }
        }
      }
    }
  }

  .bottom_btns {
    margin-top: 16px;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;

    .left {
      display: flex;
      align-items: center;
      gap: 0 16px;

      .del_text {
        @include btn_plain(#EFEFEF, #E95756) {
          background: #EFEFEF;
          border-radius: 4px;
          font-family: PingFangSC, PingFang SC, sans-serif;
          font-weight: 500;
          font-size: 14px;
          padding: 4px 12px;
          box-sizing: border-box;
        }
      }

      .close_text {
        @include btn_plain(#EFEFEF, #666666) {
          background: #EFEFEF;
          border-radius: 4px;
          font-family: PingFangSC, PingFang SC, sans-serif;
          font-weight: 500;
          font-size: 14px;
          padding: 4px 12px;
          box-sizing: border-box;
        }
      }
    }

    .right {

    }
  }
}

.loading_item {
  width: 100%;
  display: flex;
  justify-content: space-between;
  border-radius: 6px;
  border: 1px solid #ebebeb;

  .loading_img_box {
    background: rgba(0, 0, 0, 0.02);
    border-radius: 6px;
    width: 100%;
    height: 120px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;

    .loading_img {
      width: 50px;
      height: 50px;
      animation: loading 1s infinite;
      margin-bottom: 16px;
    }

    .loading_text {
      font-size: 14px;
      color: #333333;
      user-select: none;
    }
  }
}

.stop_loading_img {
  margin-right: 4px;
  width: 10px;
  height: 10px;
  animation: f_loading 1s infinite;
}

@keyframes loading {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

@keyframes f_loading {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(-360deg);
  }
}

::v-deep .el-dialog__wrapper {
  overflow: hidden;
}
</style>
